package img

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"gitee.com/bobo-rs/creative-framework/pkg/ifont"
	"github.com/disintegration/imaging"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/os/gfile"
	"github.com/icza/gox/imagex/colorx"
	"golang.org/x/image/font"
	"golang.org/x/image/font/opentype"
	"image"
	"image/color"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

type IHandle struct {
	img            image.Image // 背景图
	path           string      // 图片路径
	fontPath       string      // 字体路径
	dir            string      // 保存附件地址
	filename       string      // 文件名
	suffix         string      // 文件名后缀
	filenameSuffix string      // 文件名拼接后缀名
}

type (
	// IOverlayItem 图片合成属性
	IOverlayItem struct {
		Src        string        `json:"path" dc:"配图地址"`
		PointX     int           `json:"point_x" dc:"位置坐标X"`
		PointY     int           `json:"point_y" dc:"位置坐标Y"`
		Opacity    float64       `json:"opacity" dc:"透明度0-1"`
		UnderColor string        `json:"under_color" dc:"配图色系"`
		DrawText   *DrawTextItem `json:"draw_texts" dc:"绘制字体文本属性"`
	}

	// DrawTextItem 绘制文本属性
	DrawTextItem struct {
		Text     string  `json:"text" dc:"文字"`
		ColorHex string  `json:"color_hex" dc:"字体颜色（二进制）"`
		TextType uint    `json:"text_type" dc:"文本类型：0空白（无需绘制）, 1文本（无需分割），2分割文本（如：价格）"`
		FontSize float64 `json:"font_size" dc:"文本字体大小"`
		TextX    int     `json:"text_x" dc:"文本X坐标"`
		TextY    int     `json:"text_y" dc:"文本Y坐标"`
		Sep      string  `json:"sep" dc:"分割符：指定文案类型"`
	}

	// FlipTypeEnums 翻转类型
	FlipTypeEnums uint
)

const (
	FlipTypeH          FlipTypeEnums = iota // 水平翻转图像
	FlipTypeV                               //垂直翻转图像
	FlipTypeTranspose                       //水平翻转图像并逆时针旋转90度
	FlipTypeTransverse                      // 垂直翻转图像并逆时针旋转90度
	FlipTypeRotate90                        // 旋转90度
	//FlipTypeRotate                          // 自定义
)

func New() *IHandle {
	return &IHandle{}
}

// Open 打开图片
func (h *IHandle) Open() (image.Image, error) {
	im, err := imaging.Open(h.path)
	if err != nil {
		return nil, gerror.Wrapf(err, `Image Image Open failed: %s；Path：%s`, err.Error(), h.path)
	}
	return im, nil
}

// SetPath 设置文件路径
func (h *IHandle) SetPath(path string) {
	h.path = path
}

// SetDir 设置路径
func (h *IHandle) SetDir(dir string) {
	h.dir = dir
}

// SetFilename 设置文件名
func (h *IHandle) SetFilename(filename string) {
	h.filename = filename
}

// SetSuffix 设置文件后缀.jpg/.png等
func (h *IHandle) SetSuffix(suffix string) {
	if !strings.Contains(suffix, ".") {
		suffix += filepath.Ext(h.path)
	}
	h.suffix = suffix
}

// SetFilenameSuffix 设置后置文件名，例如：thump_800x800
func (h *IHandle) SetFilenameSuffix(filenameSuffix string) {
	h.filenameSuffix = `-` + filenameSuffix
}

// SetImg 设置背景图
func (h *IHandle) SetImg(img image.Image) {
	h.img = img
}

// SetFontPath 设置字体路径
func (h *IHandle) SetFontPath(path string) {
	h.fontPath = path
}

// Overlay 图片合成
func (h *IHandle) Overlay(images ...IOverlayItem) (err error) {
	if len(images) == 0 {
		return gerror.New(`Empty Images`)
	}

	// 打开背景图
	if err = h.IsOpen(); err != nil {
		return err
	}

	// 图片合成
	var (
		dstImage = h.img       // Copy背景图
		ift      = ifont.New() // 加载字体
		srcImage image.Image
	)

	// 加载字体
	if len(h.fontPath) > 0 {
		if err = ift.LoadFont(h.fontPath); err != nil {
			return err
		}
	}

	// 批量循环处理
	for _, item := range images {
		// 绘制文本
		srcImage, err = h.OverlayDrawText(item, ift)
		if err != nil {
			return err
		}
		// 合成图片
		dstImage = imaging.Overlay(dstImage, srcImage, image.Point{item.PointX, item.PointY}, item.Opacity)
	}

	// 赋值到图片
	h.img = dstImage
	return nil
}

// OverlayDrawText 图片合成绘制文本
func (h *IHandle) OverlayDrawText(item IOverlayItem, ift *ifont.IFont) (srcImg image.Image, err error) {
	// 实例字体
	if ift == nil {
		// 加载字体
		ift = ifont.New()
		if err = ift.LoadFont(h.fontPath); err != nil {
			return nil, err
		}
	}

	// 打开图片文件
	srcImg, err = imaging.Open(item.Src)
	if err != nil {
		return nil, gerror.Wrapf(err, `Sub Image Open failed: %s, Image Src %s`, err.Error(), item.Src)
	}

	// 是否重绘图片颜色
	if len(item.UnderColor) > 0 {
		srcImg, err = h.ImageColorToConvert(srcImg, item.UnderColor)
		if err != nil {
			return nil, err
		}
	}

	// 绘制字体，无需绘制文字
	if item.DrawText == nil || item.DrawText.TextType == 0 {
		return
	}
	ift.SetFontItem(ifont.IFont{
		BgkImage: srcImg,
		Point: image.Point{
			X: item.DrawText.TextX,
			Y: item.DrawText.TextY,
		},
		FaceOptions: &opentype.FaceOptions{
			Size:    item.DrawText.FontSize,
			Hinting: font.HintingFull,
		},
		IsSep: item.DrawText.TextType == 2,
		Sep:   item.DrawText.Sep,
	})
	// 绘制文字
	err = ift.DrawText(item.DrawText.Text, item.DrawText.ColorHex)
	if err != nil {
		return nil, err
	}

	srcImg = ift.BgkImage
	return
}

// ImageColorToConvert 转换图片颜色
func (h *IHandle) ImageColorToConvert(originImg image.Image, colorHex string) (image.Image, error) {
	if originImg == nil {
		return nil, gerror.New(`The origin image is nil`)
	}

	// 解析颜色
	modifyColor, err := h.ParseHexColor(colorHex)
	if err != nil {
		return nil, err
	}

	// 将修改颜色转换为NRGBA格式
	modifyNRGBA := ColorToNRGBA(modifyColor)

	// 获取图片宽度
	bounds := originImg.Bounds()

	// 创建一个新的完整图
	copyImg := image.NewNRGBA(bounds)

	// 按Y坐标像素循环
	for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
		// 按X坐标处理循环处理
		for x := bounds.Min.X; x < bounds.Max.X; x++ {

			// 获取原始图片的像素颜色,并将原始颜色转换为NRGBA格式以便处理
			originalNRGBA := ColorToNRGBA(originImg.At(x, y))

			// 应用新颜色的RGB值，但保留原始Alpha值
			copyImg.Set(x, y, color.NRGBA{
				modifyNRGBA.R, modifyNRGBA.G, modifyNRGBA.B, originalNRGBA.A,
			})
		}
	}
	// 返回重新绘制图片
	return copyImg, nil
}

// ParseHexColor 解析二进制颜色值
func (f *IHandle) ParseHexColor(colorHex string) (color.Color, error) {
	// 解析二进制颜色
	c, err := colorx.ParseHexColor(colorHex)
	if err != nil {
		return nil, gerror.Wrapf(err, `Pares font hex color failed , %s`, err.Error())
	}
	return c, nil
}

// Sharpen 图片锐化处理
func (h *IHandle) Sharpen(sigma float64) (err error) {
	if h.img == nil {
		h.img, err = h.Open()
		if err != nil {
			return err
		}
	}
	h.img = imaging.Sharpen(h.img, sigma)
	// 设置文件名后缀
	h.SetSuffix(`sharpen`)
	return nil
}

// Blur 图片模糊
func (h *IHandle) Blur(sigma float64) (err error) {
	if h.img == nil {
		h.img, err = h.Open()
		if err != nil {
			return err
		}
	}
	h.img = imaging.Blur(h.img, sigma)
	// 设置文件名后缀
	h.SetSuffix(`blur`)
	return nil
}

// Flip 翻转图片
func (h *IHandle) Flip(flipType FlipTypeEnums) (err error) {
	if h.img == nil {
		h.img, err = h.Open()
		if err != nil {
			return err
		}
	}
	// 翻转图片
	switch flipType {
	case FlipTypeH:
		h.img = imaging.FlipH(h.img)
	case FlipTypeV:
		h.img = imaging.FlipV(h.img)
	case FlipTypeTranspose:
		h.img = imaging.Transpose(h.img)
	case FlipTypeTransverse:
		h.img = imaging.Transverse(h.img)
	case FlipTypeRotate90:
		h.img = imaging.Rotate90(h.img)
	default:

	}
	// 设置文件名后缀
	h.SetSuffix(`flip` + strconv.Itoa(int(flipType)))
	return nil
}

// Rotate 自定义翻转图片
func (h *IHandle) Rotate(angle float64, bgColor color.Color) (err error) {
	if h.img == nil {
		h.img, err = h.Open()
		if err != nil {
			return err
		}
	}
	h.img = imaging.Rotate(h.img, angle, bgColor)
	// 设置文件名后缀
	h.SetSuffix(`rotate`)
	return nil
}

// Corp 按指定边界进行裁剪
func (h *IHandle) Corp(rect image.Rectangle) (err error) {
	if err = h.IsOpen(); err != nil {
		return err
	}
	// 按指定边界进行裁剪
	h.img = imaging.Crop(h.img, rect)
	// 设置文件名后缀
	h.SetSuffix(`corp`)
	return nil
}

// CropAnchor 指定定位点和要裁剪的宽高进行裁剪
func (h *IHandle) CropAnchor(width, height int) error {
	if err := h.IsOpen(); err != nil {
		return err
	}
	// 指定定位点和要裁剪的宽高进行裁剪
	h.img = imaging.CropAnchor(h.img, width, height, imaging.Center)
	// 设置文件名后缀
	h.SetSuffix(`crop_anchor`)
	return nil
}

// CropCenter 剪切出指定大小的矩形区域
func (h *IHandle) CropCenter(width, height int) error {
	if err := h.IsOpen(); err != nil {
		return err
	}
	h.img = imaging.CropCenter(h.img, width, height)
	// 设置文件名后缀
	h.SetSuffix(`crop_center`)
	return nil
}

// Thumb 生成缩略图
func (h *IHandle) Thumb(width, height int, resFilters ...imaging.ResampleFilter) error {
	if err := h.IsOpen(); err != nil {
		return err
	}
	h.img = imaging.Thumbnail(h.img, width, height, h.setResampleFilter(resFilters...))
	// 设置文件名后缀
	h.SetSuffix(fmt.Sprintf(`thumb-%dX%d`, width, height))
	return nil
}

// Resize 使用Lanczos过滤器将srcImage的调整大小
func (h *IHandle) Resize(width, height int, resFilters ...imaging.ResampleFilter) error {
	if err := h.IsOpen(); err != nil {
		return err
	}
	// 使用Lanczos过滤器将srcImage的调整大小
	h.img = imaging.Resize(h.img, width, height, h.setResampleFilter(resFilters...))
	// 设置文件名后缀
	h.SetSuffix(fmt.Sprintf(`resize-%dX%d`, width, height))
	return nil
}

// Fit 缩小srcImage以适应800x600px的边界框。
func (h *IHandle) Fit(width, height int, resFilters ...imaging.ResampleFilter) error {
	if err := h.IsOpen(); err != nil {
		return err
	}
	// 缩小srcImage以适应800x600px的边界框。
	h.img = imaging.Fit(h.img, width, height, h.setResampleFilter(resFilters...))
	// 设置文件名后缀
	h.SetSuffix(fmt.Sprintf(`fit-%dX%d`, width, height))
	return nil
}

// Fill 调整srcImage的大小并裁剪以填充100x100px的区域。
func (h *IHandle) Fill(width, height int, resFilters ...imaging.ResampleFilter) error {
	if err := h.IsOpen(); err != nil {
		return err
	}
	// 调整srcImage的大小并裁剪以填充100x100px的区域。
	h.img = imaging.Fill(h.img, width, height, imaging.Center, h.setResampleFilter(resFilters...))
	// 设置文件名后缀
	h.SetSuffix(fmt.Sprintf(`fill-%dX%d`, width, height))
	return nil
}

// IsOpen 检测是否打开图片
func (h *IHandle) IsOpen() (err error) {
	if h.img == nil {
		h.img, err = h.Open()
		if err != nil {
			return err
		}
	}
	return nil
}

// Save 保存图片
func (h *IHandle) Save() (err error) {
	if !gfile.IsDir(h.dir) {
		if h.dir == "" {
			h.dir = filepath.Dir(h.path) + `/`
		}
		// 创建目录
		if err = os.MkdirAll(h.dir, os.ModePerm); err != nil {
			return gerror.Wrapf(err, `Create Dir Failed: %s, Path: %s`, err.Error(), h.dir)
		}
	}
	// 文件名是否为空
	if len(h.filename) == 0 {
		h.SetFilename(gfile.Name(h.path))
	}

	// 文件名是否含有后缀地址
	if !strings.Contains(h.filename, `.`) {
		// 拼接文件名后缀
		h.filename += h.suffix
	}

	// 未找到需要保存的图片
	if h.img == nil {
		return gerror.New(`The image that needs to be saved does not exist`)
	}

	// 保存图片
	if err = imaging.Save(h.img, h.dir+h.filename); err != nil {
		return gerror.Wrapf(err, `Save Image failed:%s， filename：%s`, err.Error(), h.dir+h.filename)
	}
	return nil
}

// GetFilePath 获取文件地址
func (h *IHandle) GetFilePath() string {
	// 相对地址去除前缀
	return strings.TrimPrefix(h.dir+h.filename, ".")
}

// ContentBytes 读取内容转为[]byte
func (h *IHandle) ContentBytes() ([]byte, error) {
	if err := h.IsOpen(); err != nil {
		return nil, err
	}

	// 扩展
	fn := h.path
	if len(fn) == 0 {
		fn = h.filename
	}
	ext, err := imaging.FormatFromFilename(fn)
	if err != nil {
		return nil, gerror.Wrapf(err, `Image file ext not exists , %s`, err.Error())
	}

	var buffer bytes.Buffer
	// 读取内容
	if err = imaging.Encode(&buffer, h.img, ext); err != nil {
		return nil, gerror.Wrapf(err, `Image read buffer failed %s`, err.Error())
	}

	return buffer.Bytes(), nil
}

// ContentString 把图片内容转换为base64字符
func (h *IHandle) ContentString() string {
	buffer, err := h.ContentBytes()
	if err != nil {
		return ""
	}
	return base64.StdEncoding.EncodeToString(buffer)
}

// ImgWH 图片高宽度
func (h *IHandle) ImgWH() (width, height int) {
	if h.img == nil {
		if err := h.IsOpen(); err != nil {
			return
		}
	}
	// 高宽度
	bounds := h.img.Bounds()
	return bounds.Dx(), bounds.Dy()
}

// Ext 文件扩展
func (h *IHandle) Ext() string {
	ext := h.path
	if len(ext) == 0 {
		ext = h.filename
	}
	return strings.TrimPrefix(strings.ToLower(filepath.Ext(ext)), ".")
}

// Base64Prefix 转换内容Base64前缀
func (h *IHandle) Base64Prefix() string {
	return fmt.Sprintf(`data:image/%s;base64,`, h.Ext())
}

// setResampleFilter 设置过滤器类型
func (h *IHandle) setResampleFilter(resFilters ...imaging.ResampleFilter) imaging.ResampleFilter {
	resFilter := imaging.Lanczos
	if len(resFilters) > 0 {
		resFilter = resFilters[0]
	}
	return resFilter
}

// ParseHexColor 解析十六进制颜色
func ParseHexColor(hex string) (color.Color, error) {
	if len(hex) != 7 || hex[0] != '#' {
		return nil, fmt.Errorf("无效的十六进制颜色格式: %s", hex)
	}
	// 将十六进制颜色转换为color.RGBA类型
	r, g, b, err := ColorHexToRGBA(hex)
	if err != nil {
		return nil, err
	}
	return color.RGBA{r, g, b, 255}, nil
}

// ColorHexToRGBA 将十六进制颜色转换为RGBA
func ColorHexToRGBA(hex string) (uint8, uint8, uint8, error) {
	var r, g, b uint8
	_, err := fmt.Sscanf(hex, "#%02x%02x%02x", &r, &g, &b)
	if err != nil {
		return 0, 0, 0, err
	}
	return r, g, b, nil
}

// ColorToNRGBA 根据指定颜色转换原始颜色
func ColorToNRGBA(originalColor color.Color) color.NRGBA {
	originalNRGBA, ok := originalColor.(color.NRGBA)
	if !ok {
		originalNRGBA = color.NRGBAModel.Convert(originalColor).(color.NRGBA)
	}
	return originalNRGBA
}
